package com.aim.bestpolicy;

import com.aim.util.BetaGenerator;
import com.aim.game.*;

import java.util.LinkedList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: User
 * Date: 5/1/14
 * Time: 11:47 PM
 * To change this template use File | Settings | File Templates.
 */
public class SimulatorMain {

    public static void main(String[] args) {
        int numOfGames = 50;
        //double scorePerformancePerSecond = 10;
        int gameLength = 4 * 60 * 1000;

        System.out.println("numOfGames: " + numOfGames);
        for (double scorePerformancePerSecond = 5; scorePerformancePerSecond <= 40; scorePerformancePerSecond += 0.5){
        simulateBestPolicy(numOfGames, scorePerformancePerSecond, gameLength);
        }



    }

    private static void simulateBestPolicy(int numOfGames, double scorePerformancePerSecond, int gameLength, long[] policyCandidates){
        simulateBestPolicy(numOfGames, scorePerformancePerSecond, gameLength, policyCandidates);
    }

    private static void simulateBestPolicy(int numOfGames, double scorePerformancePerSecond, int gameLength) {
        int from = 3;
        long[] policyCandidates = new long[40 - from + 1];
        for (int i = from; i < 40; i++) {
            policyCandidates[i-from] = i * 1000;
        }

        simulateBestPolicy(numOfGames, scorePerformancePerSecond, gameLength, from, policyCandidates);
    }

    private static void simulateBestPolicy(int numOfGames, double scorePerformancePerSecond, int gameLength, int from, long[] policyCandidates) {
        double scorePerformancePerMillis = scorePerformancePerSecond / 1000;
        GameParam gameParam = new GameParam();
        gameParam.gameLength = gameLength; //5 minutes
        gameParam.timeInterval = 100;

        gameParam.costTable = new CostTable();
        gameParam.costTable.setOccurCost(MC.FIX, 0);
        gameParam.costTable.setOccurCost(MC.M1, 40);
        gameParam.costTable.setOccurCost(MC.M2, 60);
        gameParam.costTable.setOccurCost(MC.M3, 80);

//      gameParam.costTable.setActionCost(MC.FIX, 5 + (4*scorePerformancePerMillis * 1000));
//      gameParam.costTable.setActionCost(MC.M1, 100 + (4*scorePerformancePerMillis * 1000));
//      gameParam.costTable.setTimeCost(MC.FIX, 0 * 1000);
//      gameParam.costTable.setTimeCost(MC.M1, 0 * 1000);

        gameParam.costTable.setActionCost(MC.FIX, 5);
        gameParam.costTable.setActionCost(MC.M1, 100);
        gameParam.costTable.setTimeCost(MC.FIX, 4 * 1000);
        gameParam.costTable.setTimeCost(MC.M1, 4 * 1000);

        gameParam.costTable.setActionCost(MC.M2, 250);
        gameParam.costTable.setActionCost(MC.M3, 500);


        gameParam.costTable.setTimeCost(MC.M2, 8 * 1000);
        gameParam.costTable.setTimeCost(MC.M3, 15 * 1000);

        //gameParam.eventGenerator = new TimeGenerator.Const(20 * 1000);
        //long betaFunctionRange = 40460 ;
        long betaFunctionRange = 33371 ;

        gameParam.eventGenerator = new BetaGenerator(2, 1, betaFunctionRange);

        GameRule gameRule = new GameRule.GameRuleBase();


        List<Player> playerList = new LinkedList<Player>();
        for (long policyCandidate : policyCandidates) {
            playerList.add(new Player.Simple(policyCandidate, scorePerformancePerMillis));
        }

        //int from = 3;

        //for (int i = from; i < 40; i++) {
        //    playerList.add(new Player.Simple(i * 1000, scorePerformancePerMillis));
        //}

        List<GameResultCollection> results = runGames(gameRule, playerList, gameParam, numOfGames);

        int maxIndex = -1;
        double maxScore = Integer.MIN_VALUE;
        System.out.println("Results list:");
        System.out.println("scorePerformancePerSecond\tpolicy\tcost\tmaintenanceCount\trepairCount");
        for (int i = 0; i < results.size(); i++) {
            GameResultCollection gameResultCollection =  results.get(i);
            double finalScore = gameResultCollection.getFinalScore();
            if (finalScore > maxScore){
                maxScore = finalScore;
                maxIndex = i + from;
            }
            System.out.println(scorePerformancePerSecond + "\t"
                    + (i + from) + "\t" + gameResultCollection.getFinalScore()
                    + "\t" + gameResultCollection.getAverageMaCountMaintenance()
                    + "\t" + gameResultCollection.getAverageRepairCount());
        }
        System.out.println("\n    ********     ");
        System.out.println("game length:\t" + (gameParam.gameLength / 1000) + "\t(seconds)");
        System.out.println("beta function range:\t" + betaFunctionRange);
        System.out.println("player performance:\t" + (scorePerformancePerMillis * 1000)  + "\t(per seconds)");
        System.out.println("\"maintenance\" duration:\t" + gameParam.costTable.getTime(MC.FIX)/1000 + "\t(seconds)");
        System.out.println("repair \"minor\" duration:\t" + gameParam.costTable.getTime(MC.M1)/1000 + "\t(seconds)");
        System.out.println("\"maintenance\" score cost:\t" + gameParam.costTable.getActionCost(MC.FIX));
        System.out.println("repair \"minor\" score cost:\t" + gameParam.costTable.getActionCost(MC.M1));
        System.out.println("best policy: do maintenance at\t" + maxIndex + "\t(sec),\t" + maxScore + "\tnetScore\t" + scorePerformancePerSecond);
    }


    public static List<GameResultCollection> runGames(GameRule gameRule, List<Player> players, GameParam gameParam, int numOfGames){
        List<GameResultCollection> resultCollections = new LinkedList<GameResultCollection>();
        for (Player player : players) {
            GameResultCollection resultCollection = new GameResultCollection();
            for (int i = 0; i < numOfGames; i++) {
                GameResult result = gameRule.runOneGame(gameParam, player);
                resultCollection.add(result);
            }
            resultCollections.add(resultCollection);

        }
        return resultCollections;
    }




}
